
import urllib
import re
import os
import Cookie

from functools import update_wrapper

import webapp2
from google.appengine.ext.webapp import template
from google.appengine.api import urlfetch
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.api import images

from bride import imageutils 

import logging

class BridePhoto(db.Model):
    photoId = db.StringProperty()
    content = db.BlobProperty()
    tb = db.BlobProperty()
    originalURL = db.LinkProperty()
    date = db.DateTimeProperty(auto_now_add=True)

class BridePhotoRaw(BridePhoto):
    pass

def PhotoRequest(urlpattern):
    """This decorator parse the reqpath of request by the re pattern(urlpattern)
    for each group in pattern, it set the attributes of request by group names and values.
    """
    urlpattern = re.compile(urlpattern)
    def _dcrtrwrap(f):
        def _wrap(*args, **argkws):
            self = args[0]
            reqpath = self.request.path
            if self.request.method=='GET' \
                   and reqpath[-1] != '/' \
                   and not '.' in os.path.basename(reqpath):
                self.error(301)
                self.response.headers['Location'] = reqpath + '/'
                self.response.out.write(reqpath+'/')
                return 
            m = urlpattern.match(self.reqpath)
            if not m:
                raise Exception('Page Not Found')
            for k in m.groupdict():
                setattr(self, k, m.group(k))
            return f(*args, **argkws)
        return update_wrapper(_wrap, f)
    return _dcrtrwrap

def cachedRequest(f):
    def _wrap(*args, **argkws):
        self = args[0]
        for k in ['If-Modified_Since','If-None-Match']:
            hdr = self.request.headers.get(k, None)
            if hdr:
                self.error(304)
                self.response.headers['Expires'] = 'Mon, 04 Oct 2110 05:42:51 GMT'
                self.response.headers['Cache-Control'] = 'max-age=446760000'
                return 
        return f(*args, **argkws)
    return update_wrapper(_wrap, f)

PWD = 'xxg'
def needPasswd(f):
    def _wrap(*args, **argkws):
        self = args[0]
        pwd = self.request.cookies.get('pwd', None)
        if not pwd or pwd != PWD:
            self.error(403)
            return 
        return f(*args, **argkws)
    return update_wrapper(_wrap, f)

class PhotoHandler(webapp2.RequestHandler):
    def initialize(self, request, response):
        webapp2.RequestHandler.initialize(self, request, response)
        m = PhotoHandler.urlpattern.match(self.request.path)
        if not m:
            raise Exception('Page Not Found')
        for k in m.groupdict():
            setattr(self, k, m.group(k))
    
    @PhotoRequest(r'/(?P<action>.+?)(?P<reqpath>/.*)')
    def get(self, *args):
        mtd = getattr(self, self.action, None)
        if mtd:
            mtd(*args)
        else:
            raise Exception('Page Not Found')
    
    @PhotoRequest(r'/(?P<photourl>.+/(?P<photoid>\d+)\.jpg)')
    def fetch(self, *args):
        ## if not users.is_current_user_admin():
        ##     self.redirect(users.create_login_url(urllib.unquote(self.request.uri)))
        ##     return
        self.photourl = urllib.unquote(self.photourl)
        
        photos = BridePhoto.all().filter('photoId = ',self.photoid).fetch(1) 
        if len(photos) == 0:
            # not exists
            ## heads = {'User-agent' : 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT)',
            ##          'referer' : webapp.Request.blank(imgurl).host_url}
            resp = urlfetch.fetch(self.photourl,
                                  method=urlfetch.GET)
            content = resp.content
            # get thumbnail first
            tb = imageutils.thumbnailimage(content)[0]
            #content = imageutils.thumbnailimage(content, 900, 600)[0]
            photo = BridePhoto(
                photoId = self.photoid,
                content = content,
                tb = tb,
                originalURL = db.Link(self.photourl)
                )
            #we save it to db
            photo.put()
        else:
            # exists
            photo = photos[0]
        photos = BridePhotoRaw.all().filter('photoId = ',self.photoid).fetch(1) 
        if len(photos) == 0:
            # not exists
            ## heads = {'User-agent' : 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT)',
            ##          'referer' : webapp.Request.blank(imgurl).host_url}
            resp = urlfetch.fetch(self.photourl,
                                  method=urlfetch.GET)
            content = resp.content
            #content = imageutils.thumbnailimage(content, 900, 600)[0]
            photo = BridePhotoRaw(
                photoId = self.photoid,
                content = content,
                originalURL = db.Link(self.photourl)
                )
            #we save it to db
            photo.put()
        else:
            # exists
            photo = photos[0]
        self.response.headers['Content-Type'] = 'image/jpeg'
        self.response.headers['Last-Modified'] = photo.date.strftime("%a, %d %b %Y %H:%M:%S GMT")
        self.response.out.write("OK")
        return
    
    @PhotoRequest(r'/(?P<photoid>\d+)\.jpg')
    @cachedRequest
    @needPasswd
    def show(self, *args):
        photos = BridePhoto.all().filter('photoId = ',self.photoid).fetch(1) 
        if len(photos) == 0:
            raise Exception('Page Not Found')
        else:
            # exists
            photo = photos[0]
        self.response.headers['Content-Length'] = str(len(photo.content))
        self.response.headers['Content-Type'] = 'image/jpeg'
        self.response.headers['Last-Modified'] = photo.date.strftime("%a, %d %b %Y %H:%M:%S GMT")
        self.response.headers['ETag'] = str(photo.photoId)
        self.response.headers['Expires'] = 'Mon, 04 Oct 2110 05:42:51 GMT'
        self.response.headers['Cache-Control'] = 'max-age=446760000'
        self.response.out.write(photo.content)
        return
    
    @PhotoRequest(r'/(?P<photoid>\d+)\.jpg')
    @cachedRequest
    @needPasswd
    def thumbnail(self, *args):
        photos = BridePhoto.all().filter('photoId = ',self.photoid).fetch(1) 
        if len(photos) == 0:
            raise Exception('Page Not Found')
        else:
            # exists
            photo = photos[0]
        self.response.headers['Content-Length'] = str(len(photo.tb))
        self.response.headers['Content-Type'] = 'image/jpeg'
        self.response.headers['Last-Modified'] = photo.date.strftime("%a, %d %b %Y %H:%M:%S GMT")
        self.response.headers['ETag'] = str(photo.photoId)
        self.response.out.write(photo.tb)
        return
    
    @PhotoRequest(r'/(?P<photoid>\d+)\.jpg')
    @cachedRequest
    @needPasswd
    def raw(self, *args):
        photos = BridePhotoRaw.all().filter('photoId = ',self.photoid).fetch(1) 
        if len(photos) == 0:
            raise Exception('Page Not Found')
        else:
            # exists
            photo = photos[0]
        self.response.headers['Content-Length'] = str(len(photo.content))
        self.response.headers['Content-Type'] = 'image/jpeg'
        self.response.headers['Last-Modified'] = photo.date.strftime("%a, %d %b %Y %H:%M:%S GMT")
        self.response.headers['ETag'] = str(photo.photoId)
        self.response.headers['Expires'] = 'Mon, 04 Oct 2110 05:42:51 GMT'
        self.response.headers['Cache-Control'] = 'max-age=446760000'
        self.response.out.write(photo.content)
        return
    
    @PhotoRequest(r'/')
    def slides(self, *args):
        photos = BridePhoto.all().order('-photoId')
        templatedic = {}
        templatedic['photos'] = photos
        self.response.out.write(template.render('../template/bride.html', templatedic))
        return
    
    @PhotoRequest(r'/(?P<pwd>.+?)/')
    def auth(self, *args):
        logging.error(self.pwd)
        if self.pwd == PWD:
            c=Cookie.BaseCookie()
            c['pwd'] = PWD
            c['pwd']['path'] = '/bride/'
            header_value = c.output(header='').lstrip()
            self.response.headers._headers.append(('Set-Cookie', header_value))
            self.response.out.write('1')
        else:
            self.response.out.write('0')
        return

class logout(webapp2.RequestHandler):
    def get(self):
        self.redirect(users.create_logout_url('/'))
        return 

def createRouting(urlpattern, reqclass):
    reqclass.urlpattern = re.compile(urlpattern)
    return (urlpattern, reqclass)

app = webapp2.WSGIApplication(
                           [createRouting('(?P<apppath>/bride)(?P<reqpath>/.*)', PhotoHandler),
                           ('/logout', logout)],
                           debug=True)

